package org.smartboot.compare;

import org.smartboot.compare.comparator.AbstractComparator;
import org.smartboot.compare.comparator.Comparator;
import org.smartboot.compare.utils.ArgumentUtils;

import java.util.HashMap;
import java.util.Map;

/**
 *
 * @author qinluo
 * @version 1.0.8
 * @since 2024-04--4 12:27
 */
@SuppressWarnings({"rawtypes"})
public class ThreadLocalComparatorRegister {

    /**
     * All direct comparator holder.
     */
    private static final ThreadLocal<Map<Class, Comparator>> COMPARATOR_MAP_HOLDER = ThreadLocal.withInitial(() -> new HashMap<>(32));

    /**
     * Customized comparator used in Map/Fields.
     */
    private static final ThreadLocal<Map<NameType, AbstractComparator>> NAME_TYPE_COMPARATOR_HOLDER = ThreadLocal.withInitial(() -> new HashMap<>(32));

    public static Comparator register(NameType nameType, AbstractComparator<?> comparator) {
        ArgumentUtils.notNull(nameType, "register namedType must not be null!");
        ArgumentUtils.notNull(comparator, "register comparator must not be null!");

        Class<?> accept = comparator.getType();
        Class<?> actual = nameType.getType();

        if (actual != accept && !accept.isAssignableFrom(actual)) {
            throw new IllegalArgumentException("register namedType must match compare!");
        }

        return NAME_TYPE_COMPARATOR_HOLDER.get().put(nameType, comparator);
    }

    public static Comparator register(Class<?> clz, Comparator<?> compare) {
        ArgumentUtils.notNull(clz, "register class must not be null!");
        if (clz == Object.class) {
            throw new IllegalArgumentException("Object.class must not override.");
        }

        if (compare instanceof AbstractComparator) {
            AbstractComparator<?> abstractCompare = (AbstractComparator<?>) compare;
            Class<?> accept = abstractCompare.getType();

            if (clz != accept && !accept.isAssignableFrom(clz)) {
                throw new IllegalArgumentException("register class must be same type with compare#getType!");
            }
        }

        return COMPARATOR_MAP_HOLDER.get().put(clz, compare);
    }

    /**
     * Unregister comparator with specified class.
     */
    public static Comparator unregister(Class<?> clazz) {
        return COMPARATOR_MAP_HOLDER.get().remove(clazz);
    }

    /**
     * Unregister comparator with namedType.
     */
    public static Comparator unregister(NameType nameType) {
        return NAME_TYPE_COMPARATOR_HOLDER.get().remove(nameType);
    }

    /**
     * Remove all registered thread-local comparators.
     */
    public static void removeAll() {
        COMPARATOR_MAP_HOLDER.remove();
        NAME_TYPE_COMPARATOR_HOLDER.remove();
    }

    public static Map<Class, Comparator> getRegisteredComparators() {
        return COMPARATOR_MAP_HOLDER.get();
    }

    public static Map<NameType, AbstractComparator> getRegisteredNameTypeComparators() {
        return NAME_TYPE_COMPARATOR_HOLDER.get();
    }

}
